// 1.var声明
var a: number = 10;
function f(): string {
  var message: string = 'hello , world';
  return message;
}
// 在其他函数内部访问相同的变量
function foo(): object {
  var a: number = 10;
  return function g(): number {
    var b: number = a + 1;
    return b
  }
}
var g: any = f();
g(); // return 11
/* 
  上面的例子里，g可以获取到foo函数里定义的a变量。 
  每当 g被调用时，它都可以访问到foo里的a变量。
  即使当 g在f已经执行完后才被调用，它仍然可以访问及修改a。
*/

function fun(): any {
  var a: number = 1;
  a = 2;
  var b: number = g();
  a = 3;
  function g(): number {
    return a;
  }
}
fun(); // return 2

// 2.作用域规则
function fu(shouldInitialize: boolean): number {
  if (shouldInitialize) {
    var x: number = 10;
  }
  return x;
}
fu(true); // reutrn 10
fu(false); // reutrn undefined

//变量x是定义在if语句里面的，但是我们却可以在语句的外面访问它。这就是var作用域或函数作用域。

// 这些作用域可能引发一些错误，其中之一就是：多次声明一个变量并不会报错：
function sumMatrix(matrix: number[][]): number { // sum Matrix和矩阵
  var sum = 0;
  for (var i = 0; i < matrix.length; i++) {
    var currentRow = matrix[i];
    for (var i = 0; i < currentRow.length; i++) {
      sum += currentRow[i];
    }
  }
  return sum;
}
//这里很容易看出一些问题，里层的for循环会覆盖变量i，因为所有i都引用相同的函数作用域内的变量。

// 3.变量获取的怪异之处
for (var i = 0; i < 10; i++) {
  setTimeout(function () {
    console.log(i);
  }, 100 * i);
} // return 10 10 10.....
/* 
  让我们花点时间考虑在这个上下文里的情况。 
  setTimeout在若干毫秒后执行一个函数，并且是在for循环结束后。 
  for循环结束后，i的值为10。 所以当函数被调用的时候，它会打印出 10！
*/
// 一个通常的解决方法是使用立即执行函数（IIFE）来捕获每次迭代时i的值：
for (var i = 0; i < 10; i++) {
  (function (i) {
    setTimeout(function () {
      console.log(i)
    }, 100 * i);
  })(i)
} // return 0 1 2 3 4 5 6 7 8 9 

/* 
  4.let声明，词法作用域或块作用域
  不能在包含它们的函数外访问。
  不能在被声明之前读或写。
  不能重复声明一个变量。
*/

function f1(input: boolean): number {
  let a = 100;
  if(input){
    let b = a + 1;
    return b;
  }
  // return b; // 报错：找不到b
  return a;
}

function f2() {
  return c;
}
// 不能在'a'被声明前调用'foo'
// 运行时应该抛出错误
// f2();
let c;

// 5.const声明 常量 不可改变

